package com.distributer.delayqueue.delayqueue.support;

import com.google.common.collect.Lists;

import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import redis.clients.jedis.Jedis;

@SuppressWarnings("all")
public class RedisSupport {

	private StringRedisTemplate template;

	public void setTemplate(StringRedisTemplate template) {
		this.template = template;
	}

	public void deleteKey(String... key) {
		this.template.delete(Lists.newArrayList(key));
	}

	public void set(String k, String v) {
		ValueOperations<String, String> ops = this.template.opsForValue();
		ops.set(k, v);
	}

	public void set(String k, String v, long var3, TimeUnit var5) {
		ValueOperations<String, String> ops = this.template.opsForValue();
		ops.set(k, v, var3, var5);
	}

	public String get(String key) {
		ValueOperations<String, String> ops = this.template.opsForValue();
		return ops.get(key);
	}

	/**
	 * 往队列中新增元素，是左面进入，也就是靠前，遵循先进后出原则
	 * 
	 * @param key 队列名称
	 * @param item 元素
	 */
	public void leftPush(String key, String item) {
		ListOperations<String, String> listOperations = template.opsForList();
		listOperations.leftPush(key, item);
	}

	/**
	 * 返回队列中指定的元素 返回列表中指定区间内的元素，区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素， 1 表示列表的第二个元素，以此类推。 你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。
	 * 
	 * @param key 队列名称
	 * @param start 开始位置
	 * @param size 结束位置
	 * @return
	 */
	public List<String> lrange(String key, int start, int size) {
		ListOperations<String, String> listOperations = template.opsForList();
		return listOperations.range(key, start, size);
	}

	/**
	 * 移除元素
	 * 
	 * @param key 队列名称
	 * @param value 元素值
	 * @return
	 */
	public boolean lrem(String key, String value) {
		try {
			ListOperations<String, String> listOperations = template.opsForList();
			/**
			 * Long remove(K key, long count, Object value); count > 0 : 从表头开始向表尾搜索，移除与 VALUE 相等的元素，数量为 COUNT 。 count < 0 : 从表尾开始向表头搜索，移除与 VALUE 相等的元素，数量为 COUNT 的绝对值。 count = 0 :
			 * 移除表中所有与 VALUE 相等的值。
			 */
			listOperations.remove(key, 1, value);
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	/**
	 * 命令用于移除并返回列表的第一个元素
	 * 
	 * @param key 队列名称
	 * @return
	 */
	public String leftPop(String key) {
		ListOperations<String, String> listOperations = template.opsForList();
		return listOperations.leftPop(key);
	}

	/**
	 * 移除队列中最后一个元素
	 * 
	 * @param key 队列名称
	 * @return
	 */
	public String rightPop(String key) {
		ListOperations<String, String> listOperations = template.opsForList();
		return listOperations.rightPop(key);
	}

	/**
	 * 往队列末尾新增元素， 顺序执行，先进先出
	 * 
	 * @param key 队列名称
	 * @param item 元素
	 */
	public void rightPush(String key, String item) {
		ListOperations<String, String> listOperations = template.opsForList();
		listOperations.rightPush(key, item);
	}

	/**
	 * 为散列添加多个key-value键值对
	 * 
	 * @param key key
	 * @param map 批量hash健与hash值
	 */
	public void hashPutAll(String key, Map<String, String> map) {
		HashOperations<String, String, String> hashOperations = template.opsForHash();
		hashOperations.putAll(key, map);
	}

	/**
	 * 为散列添加或者覆盖一个 key-value键值对
	 * 
	 * @param key key
	 * @param hashKey hash健
	 * @param hashValue hash值
	 */
	public void hashPut(String key, String hashKey, String hashValue) {
		HashOperations<String, String, String> hashOperations = template.opsForHash();
		hashOperations.put(key, hashKey, hashValue);
	}

	/**
	 * 得到某个散列中key的hash值
	 * 
	 * @param key key
	 * @param mapKey hash健
	 * @return
	 */
	public String getHashKey(String key, String mapKey) {
		HashOperations<String, String, String> hashOperations = template.opsForHash();
		return hashOperations.get(key, mapKey);
	}

	/**
	 * 获取散列中所有的key集合
	 * 
	 * @param key
	 * @return
	 */
	public Set<String> getHashKeys(String key) {
		HashOperations<String, String, String> hashOperations = template.opsForHash();
		return hashOperations.keys(key);
	}

	/**
	 * 删除hash中的指定key
	 */
	public void deleteHashKeys(String key, Object... keys) {
		HashOperations<String, String, String> hashOperations = template.opsForHash();
		hashOperations.delete(key, keys);
	}

	/**
	 * 得到多个key的值。
	 * 
	 * @param key
	 * @param keys hash健集合
	 * @return
	 */
	public List<String> getHashKeys(String key, Collection<String> keys) {
		HashOperations<String, String, String> hashOperations = template.opsForHash();
		return hashOperations.multiGet(key, keys);
	}

	/**
	 * 获取散列的value集合
	 * 
	 * @param key
	 * @return
	 */
	public List<String> hashgetAll(String key) {
		HashOperations<String, String, String> hashOperations = template.opsForHash();
		List<String> lst = hashOperations.values(key);
		return lst;
	}

	// zset.
	/**
	 * 键为K的集合，offerset和count是限制条件，从索引1开始找到count个元素=子集， 从子集中找到Smin<=score<=Smax的元素集合，返回Set<V>，正序
	 * 
	 * @param key setkey
	 * @param min
	 * @param max
	 * @param offset 初始偏移量
	 * @param count 查询数量
	 * @return
	 */
	public Set<String> zrangeByScore(String key, double min, double max, int offset, int count) {
		ZSetOperations<String, String> zset = template.opsForZSet();

		Set<String> datas = zset.rangeByScore(key, min, max, offset, count);
		return datas;
	}

	/**
	 * 键为K的集合，offerset和count是限制条件，从索引1开始找到count个元素=子集， 从子集中找到Smin<=score<=Smax的元素集合，返回泛型接口（包括score和value），正序
	 * 
	 * @param key
	 * @param min
	 * @param max
	 * @param offset
	 * @param count
	 * @return
	 */
	public Set<ZSetOperations.TypedTuple<String>> zrangeByScoreWithScores(String key, double min, double max, int offset, int count) {
		ZSetOperations<String, String> zset = template.opsForZSet();
		Set<ZSetOperations.TypedTuple<String>> set = zset.rangeByScoreWithScores(key, min, max, offset, count);
		return set;
	}

	/**
	 * 添加value到排序集key，或者score如果已存在则更新它
	 * 
	 * @param key
	 * @param itemKey 元素值
	 * @param score
	 * @return
	 */
	public boolean zadd(String key, String itemKey, double score) {
		ZSetOperations<String, String> zset = template.opsForZSet();
		return zset.add(key, itemKey, score);
	}

	public Long zrem(String key, String itemKey) {
		ZSetOperations<String, String> zset = template.opsForZSet();
		return zset.remove(key, itemKey);
	}

	public Boolean setNx(final String key, final String value) {
		final org.springframework.data.redis.serializer.RedisSerializer redisSerializer = template.getKeySerializer();
		final org.springframework.data.redis.serializer.RedisSerializer redisValueSerializer = template.getValueSerializer();
		return template.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				return connection.setNX(redisSerializer.serialize(key), redisValueSerializer.serialize(value));
			}
		});
	}

	public Boolean pExpire(final String key, final long timeout) {
		final org.springframework.data.redis.serializer.RedisSerializer redisSerializer = template.getKeySerializer();
		return template.execute(new RedisCallback<Boolean>() {
			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
				return connection.pExpire(redisSerializer.serialize(key), timeout);
			}
		});
	}

	/**
	 * command GETSET key value
	 */
	public String getSet(final String key, final String value) {
		final org.springframework.data.redis.serializer.RedisSerializer redisSerializer = template.getKeySerializer();
		final org.springframework.data.redis.serializer.RedisSerializer redisValueSerializer = template.getValueSerializer();
		return template.execute(new RedisCallback<String>() {
			@Override
			public String doInRedis(RedisConnection connection) throws DataAccessException {
				byte[] b = connection.getSet(redisSerializer.serialize(key), redisValueSerializer.serialize(value));
				return template.getStringSerializer().deserialize(b);
			}
		});
	}

	public Jedis getJedis() {
		return (Jedis) template.getConnectionFactory().getConnection().getNativeConnection();
	}
}